/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dal/string_sequence.h"
#include <string.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif

#define CHECK_STRING_SEQ(str_seq, command)                                                         \
    if ((str_seq)->strs == NULL) {                                                                 \
        command;                                                                                   \
    }

int string_seq_init(StringSeq_t* str_seq, uint64_t capacity)
{
    if (str_seq->strs != NULL || str_seq->length != 0 || str_seq->capacity != 0) {
        return -1;
    }

    uint64_t _capacity = capacity;
    if (0 == _capacity) {
        _capacity = DEFAULT_STR_SEQ_CAPACITY;
    }
    str_seq->capacity = _capacity;
    str_seq->strs = (dal_string_t*)malloc(sizeof(dal_string_t) * _capacity);
    str_seq->length = 0;
    return str_seq->strs != NULL ? 0 : -1;
}
int string_seq_reset(StringSeq_t* str_seq)
{
    CHECK_STRING_SEQ(str_seq, return -1)
    string_seq_clear(str_seq);
    free(str_seq->strs);
    str_seq->strs = NULL;
    str_seq->length = 0;
    str_seq->capacity = 0;
    return 0;
}

int string_seq_clear(StringSeq_t* str_seq)
{
    CHECK_STRING_SEQ(str_seq, return -1)

    FOR_ALL_STRING(str_seq, str, {
        free(str.str);
        str.str = NULL;
        str.length = 0;
    });
    memset(str_seq->strs, 0, str_seq->capacity * sizeof(dal_string_t));
    str_seq->length = 0;
    return 0;
}

int string_seq_expansion(StringSeq_t* str_seq, uint64_t capacity)
{
    dal_string_t* _new_handle = (dal_string_t*)malloc(sizeof(dal_string_t) * capacity);
    if (!_new_handle) {
        return -1;
    }
    if (str_seq->strs != NULL) {
        memcpy(_new_handle, str_seq->strs, sizeof(dal_string_t) * str_seq->length);
        free(str_seq->strs);
    }

    str_seq->strs = _new_handle;
    str_seq->capacity = capacity;
    return 0;
}

int string_seq_push(StringSeq_t* str_seq, dal_string_t* str)
{
    CHECK_STRING_SEQ(str_seq, return -1)
    if (str_seq->capacity <= str_seq->length) {
        if (string_seq_expansion(str_seq, str_seq->capacity + DEFAULT_STR_SEQ_CAPACITY) <= 0) {
            return -1;
        }
    }
    str_seq->strs[str_seq->length].str = (char*)malloc(str->length + 1);
    memset(str_seq->strs[str_seq->length].str, 0, str->length + 1);
    memcpy(str_seq->strs[str_seq->length].str, str->str, str->length);
    str_seq->strs[str_seq->length].length = str->length;
    ++(str_seq->length);

    return 0;
}

int string_seq_pop(StringSeq_t* str_seq)
{
    CHECK_STRING_SEQ(str_seq, return -1)
    if (0 >= str_seq->length) {
        return -1;
    }
    free(str_seq->strs[str_seq->length - 1].str);
    str_seq->strs[str_seq->length - 1].str = NULL;
    str_seq->strs[str_seq->length - 1].length = 0;
    --(str_seq->length);
    return 0;
}

uint64_t string_seq_size(StringSeq_t* str_seq)
{
    CHECK_STRING_SEQ(str_seq, return -1)
    return str_seq->length;
}

int string_seq_get(StringSeq_t* str_seq, dal_string_t* str, int index)
{
    CHECK_STRING_SEQ(str_seq, return -1)
    if (str == NULL || (str->length > 0 && str->str == NULL) || index < 0) {
        return -1;
    }

    if (str->str) {
        free(str->str);
    }

    str->str = (char*)malloc(str_seq->strs[index].length + 1);
    memset(str->str, 0, str_seq->strs[index].length + 1);
    memcpy(str->str, str_seq->strs[index].str, str_seq->strs[index].length);

    str->length = str_seq->strs[index].length;
    return 0;
}

int string_seq_set(StringSeq_t* str_seq, dal_string_t* str, int index)
{
    CHECK_STRING_SEQ(str_seq, return -1)
    if (str == NULL || str->length <= 0 || str->str == NULL || index < 0 ||
        index >= str_seq->length) {
        return -1;
    }

    free(str_seq->strs[index].str);
    str_seq->strs[index].str = (char*)malloc(str->length + 1);

    if (str_seq->strs[index].str == NULL) {
        return -1;
    }

    memcpy(str_seq->strs[index].str, str->str, str->length);
    str_seq->strs[index].length = str->length;
    return 0;
}

#ifdef __cplusplus
}
#endif